#include "w25n01gv.h"

#define SPI_CS_LOW() LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4)
#define SPI_CS_HIGH() LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4)


static void spi_config(void)
{
    LL_SPI_InitTypeDef SPI_InitStruct = {0};

    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* Enable clock */
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
    LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
    /** SPI1 Pin config
    PA5   ------> SPI1_SCK
    PA6   ------> SPI1_MISO
    PA7   ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = LL_GPIO_PIN_4;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_3;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_3;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_3;
    LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* SPI1 parameter configuration*/
    SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
    SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
    SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
    SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH;
    SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
    SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
    SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;
    SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
    SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
    SPI_InitStruct.CRCPoly = 0x0U;
    LL_SPI_Init(SPI1, &SPI_InitStruct);

    LL_SPI_Enable(SPI1);

	// wp and hold pin
	GPIO_InitStruct.Pin = LL_GPIO_PIN_2 | LL_GPIO_PIN_3;
	GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
	GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
	GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
	LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_2);
	LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_3);
}

unsigned char SPI_ReadWriteByte(unsigned char TxData)
{
    /* loop while data register in not emplty */
    while (0 == LL_SPI_IsActiveFlag_TXE(SPI1))
        ;

    /* send byte through the SPI0 peripheral */
    LL_SPI_TransmitData8(SPI1, TxData);

    /* wait to receive a byte */
    while (0 == LL_SPI_IsActiveFlag_RXNE(SPI1))
        ;

    /* return the byte read from the SPI bus */
    return LL_SPI_ReceiveData8(SPI1);    
}


/*---------------------------------以下为接口----------------------------------*/
/*--------------------------请根据自己的实际情况修改---------------------------*/

/*
函数原型：void FlashDelay(u16 n);
函数功能：延时
参数：n 延时的毫秒数
返回值：无
*/
void (*FlashDelay)(unsigned short n) = (void (*)(unsigned short))&LL_mDelay;

/*
函数原型：u8 FlashRW(u8 dat);
函数功能：SPI读写一字节
参数：dat 要写入的数据
返回值：读出的数据
*/
unsigned char (*FlashRW)(unsigned char dat) = &SPI_ReadWriteByte;

/*
函数原型：void FlashEnable(u8 s);
函数功能：SPI片选
参数：s 片选状态，0未选中，非0选中;
返回值：无
*/
void FlashEnable(unsigned char s)
{
	if (s) 
	{
		SPI_CS_LOW();
	}
	else
	{
		SPI_CS_HIGH();
	}
}

/*--------------------------------以下为驱动程序-------------------------------*/

unsigned char FlashReset(void)
{
	FlashEnable(1);
	FlashRW(FLASH_DEVICE_RESET);
	FlashEnable(0);
	FlashDelay(1);//手册上说复位时间约为5-500us，这里延时1ms
	if(FlashWaitBusy(100))
	{
		return 1;//等待复位超时
	}
	return 0;
}

unsigned char FlashInit(void)
{
    unsigned int id = 0;
    
    // 1. 初始化SPI接口
    spi_config();
//    FlashDelay(10);  // 短延时确保SPI稳定
    
    // 2. 确保Flash退出任何特殊状态
    FlashReset();  // 发送复位命令(0xFF)
//    FlashDelay(50);  // 复位后等待足够时间
    
    // 3. 释放掉电模式(如果处于该模式)
//    FlashEnable(1);
//    FlashRW(FLASH_RELEASE_POWER_DOWN);  // 0xAB
//    FlashEnable(0);
//    FlashDelay(5);  // 短延时
    
    // 4. 读取JEDEC ID
    FlashEnable(1);
    FlashRW(FLASH_JEDEC_ID);  // 0x9F
    
    // 读取3字节ID (忽略第4个字节)
    FlashRW(0x00);
    id |= FlashRW(0xFF) << 16;  // Manufacturer ID (应得0xEF)
    id |= FlashRW(0xFF) << 8;   // Memory Type (应得0xAA)
    id |= FlashRW(0xFF);        // Capacity (应得0x21)
    FlashEnable(0);
    
    rt_kprintf("Flash ID: 0x%06X\n", id & 0xFFFFFF);

    
    if((id & 0xFFFFFF) != FLASH_ID_W25N01GV) {
        rt_kprintf("Error: Wrong Flash model (Expected 0xEFAA21, got 0x%06X)\n", id & 0xFFFFFF);
        return 1; // 芯片型号不对
    }

	if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BBM_LUT_FULL)
	{
		//坏块映射表已满，继续使用不能保证数据的正确性
		return 2;
	}
	//芯片设置
	id = FlashReadStatusRegister(FLASH_STATUS_REG1_ADDR);
	id = 0;//禁用所有写保护
	FlashWriteStatusRegister(FLASH_STATUS_REG1_ADDR, id & 0x000000FF);

	id = FlashReadStatusRegister(FLASH_STATUS_REG2_ADDR);
	id |= (0x10 | 0x80);//开启ECC，禁用读取缓冲区
	FlashWriteStatusRegister(FLASH_STATUS_REG2_ADDR, id & 0x000000FF);

	return 0;
}

//等待芯片操作完成，时间单位ms
unsigned char FlashWaitBusy(unsigned short int timeout)
{
	while(timeout--)
	{
		if((FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BUSY) != FLASH_SR_BUSY)
		{
			return 0;//等待结束
		}
		FlashDelay(1);
	}
	return 1;//等待超时
}

void FlashWriteEnable(void)
{
	FlashEnable(1);
	FlashRW(FLASH_WRITE_ENABLE);
	FlashEnable(0);
}

void FlashWriteDisable(void)
{
	FlashEnable(1);
	FlashRW(FLASH_WRITE_DISABLE);
	FlashEnable(0);
}

unsigned char FlashReadStatusRegister(unsigned char RegAddr)
{
	unsigned char tmp;

	FlashEnable(1);
	FlashRW(FLASH_READ_STATUS_REGISTER);
	FlashRW(RegAddr);
	tmp = FlashRW(0x00);
	FlashEnable(0);

	return tmp;
}

void FlashWriteStatusRegister(unsigned char RegAddr, unsigned char Value)
{
	FlashEnable(1);
	FlashRW(FLASH_WRITE_STATUS_REGISTER);
	FlashRW(RegAddr);
	FlashRW(Value);
	FlashEnable(0);
}

//读取一页，返回值为ECC校验结果
unsigned char FlashReadPage(unsigned short int page, unsigned char *buf)
{
	unsigned short int i = 0;

	//输入要读取的页地址
	FlashEnable(1);
	FlashRW(FLASH_PAGE_DATA_READ);
	FlashRW(0x00);
	FlashRW((unsigned char)(page >> 8));
	FlashRW((unsigned char)(page & 0x00FF));
	FlashEnable(0);
	FlashDelay(1);
	
	//开始读取
	FlashEnable(1);
	FlashRW(FLASH_READ);
	FlashRW(0x00);
	FlashRW(0x00);
	FlashRW(0x00);
	//三个空字节后开始接收数据
	for(i = 0; i < 2048; i++)
	{
		*buf = FlashRW(0x00);
		buf++;
	}
	FlashEnable(0);

	return FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & 0x30;
}

//写入一页，0成功，1失败
unsigned char FlashWritePage(unsigned short int page, unsigned char *buf)
{
	unsigned short int i = 0;
	
	FlashWriteEnable();
	FlashDelay(1);
	
	//将数据送到Flash
	FlashEnable(1);
	FlashRW(FLASH_PROGRAM_DATA_LOAD);
	FlashRW(0x00);//填充字节
	FlashRW(0x00);//填充字节
	for(i = 0; i < 2048; i++)
	{
		FlashRW(*buf);
		buf++;
	}
	FlashEnable(0);
	FlashDelay(1);
	
	//执行写入操作
	FlashEnable(1);
	FlashRW(FLASH_PROGRAM_ECECUTE);
	FlashRW(0x00);
	FlashRW((unsigned char)(page >> 8));
	FlashRW((unsigned char)(page & 0x00FF));
	FlashEnable(0);

	FlashWaitBusy(100);//等待写入完成

	//检查是否写入成功
	if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_WRITE_FAIL)
	{
		return 1;
	}
	return 0;
}

//擦除区块，0成功，1失败
unsigned char FlashBlockErase(unsigned short int BlockNum)
{
	FlashWriteEnable();
	FlashEnable(1);
	FlashRW(FLASH_BLOCK_ERASE);
	FlashRW((unsigned char)(0x00));
	FlashRW((unsigned char)(BlockNum >> 8));
	FlashRW((unsigned char)(BlockNum & 0x00FF));
	FlashEnable(0);
	if(FlashWaitBusy(100))
	{
		//等待擦除完成，手册上说最大不超过10ms
		return 1;
	}
	
	//检查是否擦除成功
	if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_ERASE_FAIL)
	{
		return 1;
	}
	return 0;
}

//区块扫描，可以用来检查擦除是否成功或扫描出厂时的坏块标记
unsigned char BlockScan(unsigned short int BlockNum)
{
	int i = 0;

	//把块地址换算成页地址
	BlockNum <<= 6;

	FlashEnable(1);
	FlashRW(FLASH_PAGE_DATA_READ);
	FlashRW(0x00);
	FlashRW((unsigned char)(BlockNum >> 8));
	FlashRW((unsigned char)(BlockNum & 0x00FF));
	FlashEnable(0);

	FlashDelay(1);
	//开始读取
	FlashEnable(1);
	FlashRW(FLASH_READ);
	FlashRW(0x00);
	FlashRW(0x00);
	FlashRW(0x00);
	//三个空字节后开始接收数据
	for(i = 0; i < 128 * 1024; i++)
	{
		if(FlashRW(0x00) != 0xFF)
		{
			FlashEnable(0);
			return 1;
		}
	}
	FlashEnable(0);

	return 0;
}

//专门用于找出出厂时的坏块标记，手册上说出厂时坏块的第一页的第一个字节会被标记为非0xFF，
unsigned char BadBlockScan(unsigned short int BlockNum)
{
	//把块地址换算成页地址
	BlockNum <<= 6;

	FlashEnable(1);
	FlashRW(FLASH_PAGE_DATA_READ);
	FlashRW(0x00);
	FlashRW((unsigned char)(BlockNum >> 8));
	FlashRW((unsigned char)(BlockNum & 0x00FF));
	FlashEnable(0);

	FlashDelay(1);
	//开始读取
	FlashEnable(1);
	FlashRW(FLASH_READ);
	FlashRW(0x00);
	FlashRW(0x00);
	FlashRW(0x00);
	//三个空字节后开始接收数据
	//出厂时，坏块的第一页的第一个字节会被标记为非0xFF，后面的就不用继续扫描了
	if(FlashRW(0x00) != 0xFF)
	{
		FlashEnable(0);
		return 1;
	}
	FlashEnable(0);

	return 0;
}

//LBA(Logical Block Address)是坏块地址，PBA(Physical Block Address)是要替换的区块地址
//返回0正常，1坏块表已满
unsigned char BadBlockMapping(unsigned short int LBA, unsigned short int PBA)
{
	if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BBM_LUT_FULL)
	{
		return 1;
	}

	FlashEnable(1);
	FlashRW(FLASH_BAD_BLOCK_MANAGEMENT);
	FlashRW((unsigned char)(LBA >> 8));
	FlashRW((unsigned char)(LBA & 0x00FF));
	FlashRW((unsigned char)(PBA >> 8));
	FlashRW((unsigned char)(PBA & 0x00FF));
	FlashEnable(0);

	return 0;
}

//Bad Block Management Look Up Table
//BBMLUT需要80字节存储（实际上应当是40个unsigned short数据）
//格式是LBA0,PBA0,LBA1,PBA1......LBA19,PBA19
void ReadBBMLUT(unsigned short int *BBMLUT)
{
	// int i = 0;

	// FlashEnable(1);
	// FlashRW(FLASH_READ_BBM_LUT);
	// FlashRW(0x00);
	// for(i = 0; i < 80; i++)
	// {
	// 	*BBMLUT = FlashRW(0x00) << 8;
	// 	BBMLUT++;
	// 	*BBMLUT |= FlashRW(0x00);
	// }
	// FlashEnable(0);

	FlashEnable(1);
    FlashRW(FLASH_READ_BBM_LUT);
    FlashRW(0x00); // 起始地址
    for(int i = 0; i < 40; i++) { // 40个unsigned short
        BBMLUT[i] = (FlashRW(0x00) << 8) | FlashRW(0x00);
    }
    FlashEnable(0);
}

//读出最后一个ECC错误的页地址
unsigned short int LastECCFailPageAddr(void)
{
	unsigned short int PageAddr = 0;

	FlashEnable(1);
	FlashRW(FLASH_LAST_ECC_FAILURE_PAGE_ADDR);
	FlashRW(0x00);
	PageAddr |= FlashRW(0x00) << 8;
	PageAddr |= FlashRW(0x00);
	FlashEnable(0);

	return PageAddr;
}

//在正式使用前建议执行一次坏块扫描
//使用前不要向Flash写入任何数据，否则可能覆盖出厂时的坏块信息
//void BadBlockManage(void)
//{
//	unsigned short int i = 0, n = 0;
//	unsigned short int BBT[40] = {0};//Bad Block Table

//	rt_kprintf("开始坏块扫描 \r\n");
//	for(i = 0; i < 1024; i++)
//	{
//		rt_kprintf("正在扫描第 %d 块 \r\n", i);
//		if(BadBlockScan(i))//快速扫描，只扫描每页的第一字节
//		{
//			rt_kprintf("第 %d 块为坏块 \r\n", i);
//			//自动填入映射表还是手动填？

//			if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BBM_LUT_FULL)
//			{
//				rt_kprintf("坏块映射表已满，无法映射 \r\n");
//			}
//			else
//			{
//				ReadBBMLUT(BBT);
//				//1000到1023一共24个Block用于替换，BBMLUT一共能保存20个映射关系
//				//多出来的4块是考虑到这20个块中还有坏块的情况
//				for(n = 0; n < 20; n++)
//				{
//					if(BBT[n * 2] == 0x0000 && BBT[n * 2 + 1] == 0x0000)
//					{
//						n += 1000;
//						BadBlockMapping(i, n);
//						rt_kprintf("第 %d 块被映射为第 %d 块 \r\n", i, n);
//						break;
//					}
//				}
//			}
//		}
//	}
//	rt_kprintf("坏块扫描结束 \r\n");
//}


void BadBlockManage(void) {
    unsigned short int i = 0, n = 0;
    unsigned short int BBT[40];
    memset(BBT, 0, sizeof(BBT)); // 初始化BBT

    rt_kprintf("开始坏块扫描 \r\n");
    for(i = 0; i < 1024; i++) {
        rt_kprintf("正在扫描第 %d 块 \r\n", i);
        if(BadBlockScan(i)) {
            rt_kprintf("第 %d 块为坏块 \r\n", i);
            if(FlashReadStatusRegister(FLASH_STATUS_REG3_ADDR) & FLASH_SR_BBM_LUT_FULL) {
                rt_kprintf("坏块映射表已满，无法映射 \r\n");
                continue;
            }
            ReadBBMLUT(BBT);
            for(n = 0; n < 20; n++) {
                if(BBT[n * 2] == 0x0000 && BBT[n * 2 + 1] == 0x0000) {
                    unsigned short replace_block = 1000 + n;
                    if(BadBlockScan(replace_block)) { // 检查替换块是否为坏块
                        rt_kprintf("替换块 %d 为坏块，跳过 \r\n", replace_block);
                        continue;
                    }
                    BadBlockMapping(i, replace_block);
                    rt_kprintf("第 %d 块被映射为第 %d 块 \r\n", i, replace_block);
                    break;
                }
            }
            if(n >= 20) {
                rt_kprintf("无可用替换块，映射失败 \r\n");
            }
        }
    }
    rt_kprintf("坏块扫描结束 \r\n");
}
